﻿namespace ClassyBlog.Specs.Acceptance
{
    using System;
    using System.Linq;
    using System.Web.Mvc;

    using Should;
    using TechTalk.SpecFlow;
    using WatiN.Core;

    using DataAccess;
    using DomainObjects;
    using ExtensionMethods;
    using Infrastructure;

    [Binding]
    public class ViewPostSteps : Step
    {
        private string slug;
        private Post post;

        [Given(@"a post with slug '(.*)' exists")]
        public void GivenAPostWithSpecifiedSlugExists(string localSlug)
        {
            slug = localSlug;
            post = ServiceLocator.GetService<IPostRepository>().FindOne(slug);
        }

        [When(@"I visit the post")]
        public void WhenIVisitThePost()
        {
            Browser.Visit("/posts/" + slug);
        }

        [Then(@"the browser should render the post meta keywords")]
        public void ThenTheBrowserShouldRenderThePostMetaKeywords()
        {
            Browser.Select("meta[name=keywords]")
                   .GetAttributeValue("content")
                   .ShouldEqual(post.MetaKeywords);
        }

        [Then(@"the browser should render the post meta description")]
        public void ThenThenTheBrowserShouldRenderThePostMetaDescription()
        {
            Browser.Select("meta[name=description]")
                   .GetAttributeValue("content")
                   .ShouldEqual(post.MetaDescription);
        }

        [Then(@"the browser should render the post author")]
        public void ThenTheBrowserShouldRenderThePostAuthor()
        {
            Browser.Select("meta[name=author]")
                   .GetAttributeValue("content")
                   .ShouldEqual(post.Author);
        }

        [Then(@"the post title should be in the page tile")]
        public void ThenThePostTitleShouldBeThePageTile()
        {
            Browser.Title.ShouldContain(post.Title);
        }

        [Then(@"the post published date should be in the post header")]
        public void ThenThePostPublishedDateShouldBeInTheArticleHeader()
        {
            var time = Browser.Select("article > header > time");

            time.GetAttributeValue("datetime")
                .ShouldEqual(post.PublishedAt.ShortFormat());

            time.Text.ShouldEqual(post.PublishedAt.LongFormat());
        }

        [Then(@"the post title should be in the post header")]
        public void ThenThePostTitleShouldBeInThePostHeader()
        {
            Browser.Select("article > header > h1")
                   .Text.ShouldEqual(post.Title);
        }

        [Then(@"the post body should be the main content")]
        public void ThenThePostBodyShouldBeTheBody()
        {
            var browserOutput = Browser.Select("article > div").InnerHtml;
            var rendererOutput = DependencyResolver.Current
                                                   .GetService<IRenderer>()
                                                   .RenderFull(post);

            rendererOutput.SimilarTo(browserOutput).ShouldBeTrue();
        }

        [Then(@"the post author name should be in the post footer")]
        public void ThenThePostAuthorNameShouldBeInThePostFooter()
        {
            Browser.Select("article > footer[role=contentinfo]")
                   .Text.ShouldContain(post.Author);
        }

        [Then(@"the post tags should be in the post footer")]
        public void ThenThePostTagsShouldBeInThePostFooter()
        {
            var tags = ((IElementContainer)Browser.Select(
                "article > footer[role=contentinfo]")).Links
                .Where(link => "tag".Equals(link.GetAttributeValue("rel")))
                .ToList();

            foreach (var tag in post.Tags)
            {
                tags.Any(e => e.Text.Equals(tag.Title)).ShouldBeTrue();
            }
        }

        [Then(@"the post footer should have the '(.*)' instruction")]
        public void ThenThePostFooterShouldHaveTheLeaveCommentsInstruction(
            string text)
        {
            Browser.Select("article > footer[role=contentinfo]")
                   .Text.ShouldContain(text);
        }

        [Then(@"the post footer should not have the '(.*)' instruction")]
        public void ThenThePostFooterShouldNotHaveTheLeaveCommentsInstruction(
            string text)
        {
            Browser.Select("article > footer[role=contentinfo]")
                   .Text.ShouldNotContain(text);
        }

        [Then(@"the browser should not include any '(.*)' scripts")]
        public void ThenTheBrowserShouldNotIncludeAnyThirdPartyScripts(
            string thirdParty)
        {
            Browser.ElementsWithTag("script")
                   .Where(script =>
                       string.IsNullOrWhiteSpace(
                       script.GetAttributeValue("src")))
                   .Any(script =>
                       script.Text.IndexOf(
                       thirdParty, StringComparison.OrdinalIgnoreCase) > 0)
                   .ShouldBeFalse();
        }

        [Given(@"a post with slug '(.*)' does not exist")]
        public void GivenAPostWithSlugDoesNotExist(string localSlug)
        {
            slug = localSlug;
            post = null;
        }

        [Then(@"the browser title should contain '(.*)'")]
        public void ThenTheBrowserTitleShouldContain404(string text)
        {
            Browser.Title.ShouldContain("404");
        }
    }
}